package com.xjrsoft.module.form.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.github.yulichang.toolkit.MPJWrappers;
import com.xjrsoft.common.annotation.XjrLog;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.YesOrNoEnum;
import com.xjrsoft.common.model.generator.FormConfig;
import com.xjrsoft.common.model.result.R;
import com.xjrsoft.common.page.ConventPage;
import com.xjrsoft.common.page.PageOutput;
import com.xjrsoft.common.utils.VoToColumnUtil;
import com.xjrsoft.module.form.dto.*;
import com.xjrsoft.module.form.entity.FormHistory;
import com.xjrsoft.module.form.entity.FormRelease;
import com.xjrsoft.module.form.entity.FormTemplate;
import com.xjrsoft.module.form.service.IFormHistoryService;
import com.xjrsoft.module.form.service.IFormReleaseService;
import com.xjrsoft.module.form.service.IFormTemplateService;
import com.xjrsoft.module.form.vo.FormTemplateListVo;
import com.xjrsoft.module.form.vo.FormTemplatePageVo;
import com.xjrsoft.module.form.vo.FormTemplateVo;
import com.xjrsoft.module.generator.dto.DataFirstPreviewDto;
import com.xjrsoft.module.generator.entity.ListConfig;
import com.xjrsoft.module.generator.entity.MenuConfig;
import com.xjrsoft.module.generator.entity.TableConfig;
import com.xjrsoft.module.generator.service.IGeneratorService;
import com.xjrsoft.module.organization.dto.UpdateRoleStatusDto;
import com.xjrsoft.module.organization.entity.Department;
import com.xjrsoft.module.organization.entity.Post;
import com.xjrsoft.module.organization.entity.Role;
import com.xjrsoft.module.organization.entity.User;
import com.xjrsoft.module.organization.vo.UserPageVo;
import com.xjrsoft.module.system.entity.CodeSchema;
import com.xjrsoft.module.system.entity.DictionaryDetail;
import com.xjrsoft.module.system.entity.Menu;
import com.xjrsoft.module.system.service.ICodeSchemaService;
import com.xjrsoft.module.system.service.IDictionarydetailService;
import com.xjrsoft.module.system.service.IMenuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 表单设计模板  前端控制器
 * </p>
 *
 * @author tzx
 * @since 2022-05-09
 */
@RestController
@RequestMapping(GlobalConstant.FORM_MODULE_PREFIX + "/template")
@Api(value = GlobalConstant.FORM_MODULE_PREFIX + "/template", tags = "自定义表单-代码生成器 模板设计")
@AllArgsConstructor
public class FormTemplateController {

    private final IFormTemplateService formTemplateService;

    private final IFormHistoryService formHistoryService;

    private final IFormReleaseService formReleaseService;

    private final IGeneratorService generatorService;

    private final ICodeSchemaService codeSchemaService;

    private final IDictionarydetailService dictionarydetailService;

    private final IMenuService menuService;



    @GetMapping(value = "/list")
    @ApiOperation(value = "表单设计模板(不分页)")
    @XjrLog(value = "表单设计模板")
    public R list(@Valid FormTemplateListDto dto) {
        List<FormTemplate> list = formTemplateService.list(Wrappers.lambdaQuery(FormTemplate.class)
                .eq(FormTemplate::getFormType, dto.getType())
                .eq(dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                .orderByDesc(FormTemplate::getCreateDate)
                .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplateListVo.class).contains(x.getProperty())));

        List<FormTemplateListVo> formTemplateListVos = BeanUtil.copyToList(list, FormTemplateListVo.class);
        return R.ok(formTemplateListVos);
    }

    @GetMapping(value = "/page")
    @ApiOperation(value = "表单设计模板(分页),过滤未启用数据")
    @XjrLog(value = "表单设计模板")
    public R page(@Valid FormTemplatePageDto dto) {

        List<Menu> list = menuService.list(Wrappers.<Menu>lambdaQuery().select(Menu::getId, Menu::getFormId, Menu::getComponent));
        List<Long> formIdList = list.stream().map(Menu::getFormId).collect(Collectors.toList());
        //因为多表关联 会有多个表都使用了id字段，  所以必须专门指定主表的Id
        IPage<FormTemplatePageVo> page = formTemplateService.selectJoinListPage(ConventPage.getPage(dto), FormTemplatePageVo.class,
                MPJWrappers.<FormTemplate>lambdaJoin().disableSubLogicDel()
                        .orderByDesc(FormTemplate::getCreateDate)
                        .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                        .eq(FormTemplate::getFormType, dto.getType())
                        .eq(ObjectUtil.isNotNull(dto.getCategory()) && dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                        .eq(FormTemplate::getEnabledMark, YesOrNoEnum.YES.getCode())
                        .in(dto.getType() == YesOrNoEnum.NO.getCode(),FormTemplate::getId, formIdList) //如果是系统表单就过滤掉在menu表里面没有的系统表单，不需要使用
                        .select(FormTemplate::getId)
                        .selectAs(User::getName, FormTemplatePageVo::getCreateUserName)
                        .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplatePageVo.class).contains(x.getProperty()))
                        .selectAs(DictionaryDetail::getName, FormTemplatePageVo::getCategoryName)
                        .leftJoin(DictionaryDetail.class, DictionaryDetail::getId, FormTemplate::getCategory)
                        .leftJoin(User.class, User::getId, FormTemplate::getCreateUserId));

        List<FormTemplatePageVo> removeRecord = new ArrayList<>();
        if (dto.getType()== YesOrNoEnum.NO.getCode()){//系统表单
            List<FormTemplatePageVo> records = page.getRecords();
            if (records.size() > 0) {
                for (FormTemplatePageVo record : records) {
                    //去menu表里面找道对应的功能名称和功能模块名称
                    Menu menu = list.stream().filter(x -> ObjectUtil.isNotEmpty(x.getFormId()) && x.getFormId().equals(record.getId())).findFirst().orElse(new Menu());
                    if (menu != null && ObjectUtil.isNotEmpty(menu.getId())) {
                        String[] split = menu.getComponent().split(StringPool.SLASH);
                        record.setFunctionalModule(split[1]);
                        record.setFunctionName(split[2]);
                    } else {
                        removeRecord.add(record);
                    }
                }
                long size = removeRecord.size();
                page.setTotal(page.getTotal() - size);
                records.removeAll(removeRecord);
                page.setRecords(records);
            }
        }

        PageOutput<FormTemplatePageVo> pageOutput = ConventPage.getPageOutput(page);
        return R.ok(pageOutput);
    }

    @GetMapping(value = "/enabled-page")
    @ApiOperation(value = "表单设计模板(分页)，不过滤未启用数据")
    @XjrLog(value = "表单设计模板")
    public R pageEnabled(@Valid FormTemplatePageDto dto) {

        //因为多表关联 会有多个表都使用了id字段，  所以必须专门指定主表的Id
        IPage<FormTemplatePageVo> page = formTemplateService.selectJoinListPage(ConventPage.getPage(dto), FormTemplatePageVo.class,
                MPJWrappers.<FormTemplate>lambdaJoin().disableSubLogicDel()
                        .orderByDesc(FormTemplate::getCreateDate)
                        .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                        .eq(FormTemplate::getFormType, dto.getType())
                        .eq(ObjectUtil.isNotNull(dto.getCategory()) && dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                        .select(FormTemplate::getId)
                        .selectAs(User::getName, FormTemplatePageVo::getCreateUserName)
                        .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplatePageVo.class).contains(x.getProperty()))
                        .selectAs(DictionaryDetail::getName, FormTemplatePageVo::getCategoryName)
                        .leftJoin(DictionaryDetail.class, DictionaryDetail::getId, FormTemplate::getCategory)
                        .leftJoin(User.class, User::getId, FormTemplate::getCreateUserId));

        PageOutput<FormTemplatePageVo> pageOutput = ConventPage.getPageOutput(page);
        return R.ok(pageOutput);
    }

    @GetMapping(value = "/info")
    @ApiOperation(value = "表单设计模板详情")
    @XjrLog(value = "表单设计模板详情")
    public R info(@RequestParam Long id) {
        FormTemplate template = formTemplateService.getById(id);
        if (template == null) {
            return R.error("找不到此数据！");
        }
        FormTemplateVo formTemplateVo = BeanUtil.toBean(template, FormTemplateVo.class);
        if (template.getFormType() == YesOrNoEnum.NO.getCode()){//系统表单
            //去menu表里面找道对应的功能名称和功能模块名称
            Menu menu = menuService.getOne(Wrappers.<Menu>lambdaQuery().eq(Menu::getFormId, template.getId()));
            if (menu != null){
                String[] split = menu.getComponent().split(StringPool.SLASH);
                formTemplateVo.setFunctionalModule(split[1]);
                formTemplateVo.setFunctionName(split[2]);
            }else {
                return R.error("找不到对应的系统表单功能名称和功能模块名称");
            }
        }
        return R.ok(formTemplateVo);
    }

    @GetMapping(value = "/info/multi")
    @ApiOperation(value = "表单设计模板详情(批量查询)")
    @XjrLog(value = "表单设计模板详情(批量查询)")
    public R multiInfo(@RequestParam String id) {
        List<FormTemplate> formTemplates = formTemplateService.listByIds(Arrays.asList(id.split(StringPool.COMMA)));
        List<FormTemplateVo> formTemplateVos = BeanUtil.copyToList(formTemplates, FormTemplateVo.class);
        return R.ok(formTemplateVos);
    }

    @PutMapping("/status")
    @ApiOperation(value = "修改表单状态")
    @XjrLog(value = "修改表单状态")
    public R updateEnabled(@Valid @RequestBody UpdateTemplateStatusDto dto) {
        //根据id修改表单enabledMark
        return R.ok(formTemplateService.update(Wrappers.<FormTemplate>update().lambda().set(FormTemplate::getEnabledMark, dto.getEnabledMark()).eq(FormTemplate::getId, dto.getId())));
    }

    @PostMapping(value = "/data-first")
    @ApiOperation(value = "数据优先 新增")
    @XjrLog(value = "数据优先新增")
    public R addDataFirst(@Valid @RequestBody AddFormDataFirstDto dto) {
        return R.ok(formTemplateService.addDataFirst(dto));
    }

    @PostMapping(value = "/code-first")
    @ApiOperation(value = "界面优先 或者  简易模板 新增")
    @XjrLog(value = "界面优先 或者 简易模板新增")
    public R addCodeFirst(@Valid @RequestBody AddFormCodeFirstDto dto) throws Exception {
        return R.ok(formTemplateService.addCodeFirst(dto));
    }

    @PutMapping(value = "/data-first")
    @ApiOperation(value = "修改数据优先")
    @XjrLog(value = "修改数据优先")
    public R updateDataFirst(@Valid @RequestBody UpdateFormDataFirstDto dto) throws JsonProcessingException {
        return R.ok(formTemplateService.updateDataFirst(dto));
    }


    @PutMapping(value = "/code-first")
    @ApiOperation(value = "修改界面优先")
    @XjrLog(value = "修改界面优先")
    public R updateCodeFirst(@Valid @RequestBody UpdateFormCodeFirstDto dto) throws Exception {
        return R.ok(formTemplateService.updateCodeFirst(dto));
    }

    @DeleteMapping
    @ApiOperation(value = "删除")
    public R delete(@Valid @RequestBody List<Long> ids) {
        formHistoryService.remove(Wrappers.lambdaQuery(FormHistory.class).in(FormHistory::getFormId, ids));
        return R.ok(formTemplateService.removeBatchByIds(ids));
    }

    @PostMapping(value = "/test-code")
    @ApiOperation(value = "表单测试代码生成器")
    @XjrLog(value = "测试表单预览代码生成器")
    public R test(@Valid @RequestBody DateTestDto dto){
        FormRelease formRelease = formReleaseService.getById(dto.getFormReleaseId());
        FormTemplate formTemplate = formTemplateService.getById(dto.getFormTemplateId());
        JSONObject configJson = JSON.parseObject(formRelease.getConfigJson());
        JSONObject formJson = JSON.parseObject(formTemplate.getFormJson());
        dto.setDatabaseId(formJson.get("databaseId").toString());
        dto.setTableConfigs(JSONObject.parseArray(formJson.getString("tableConfigs"),TableConfig.class));
        dto.setFormJson(JSON.parseObject(formJson.getString("formJson"),FormConfig.class));
        dto.setListConfig(JSON.parseObject(configJson.getString("listConfig"), ListConfig.class));
        dto.setMenuConfig(JSON.parseObject(configJson.getString("menuConfig"), MenuConfig.class));
        dto.setOutputConfig(dto.getOutputConfig());
        return R.ok(generatorService.getPreviewCodes(BeanUtil.toBean(dto, DataFirstPreviewDto.class)));
    }

    @GetMapping(value = "/desk-form-page")
    @ApiOperation(value = "桌面设计-复杂列表页使用(分页),过滤未启用数据")
    @XjrLog(value = "表单设计模板")
    public R deskFormPage(@Valid FormTemplateDeskPageDto dto) {
        //只需要已发布的，和系统表单的数据
        List<Long> releaseIds = formReleaseService.list().stream().map(FormRelease::getFormId).collect(Collectors.toList());
        //因为多表关联 会有多个表都使用了id字段，  所以必须专门指定主表的Id
        IPage<FormTemplatePageVo> page = formTemplateService.selectJoinListPage(ConventPage.getPage(dto), FormTemplatePageVo.class,
                MPJWrappers.<FormTemplate>lambdaJoin().disableSubLogicDel()
                        .orderByDesc(FormTemplate::getCreateDate)
                        .like(StrUtil.isNotBlank(dto.getKeyword()), FormTemplate::getName, dto.getKeyword())
                        .eq(FormTemplate::getFormType, dto.getType())
                        .eq(ObjectUtil.isNotNull(dto.getCategory()) && dto.getCategory() != 0, FormTemplate::getCategory, dto.getCategory())
                        .eq(FormTemplate::getEnabledMark,YesOrNoEnum.YES.getCode())
                        .in(dto.getType() == YesOrNoEnum.YES.getCode() && CollectionUtil.isNotEmpty(releaseIds),FormTemplate::getId,releaseIds) //自定义表单需要过滤出来已发布的数据
                        .select(FormTemplate::getId)
                        .selectAs(User::getName, FormTemplatePageVo::getCreateUserName)
                        .select(FormTemplate.class, x -> VoToColumnUtil.fieldsToColumns(FormTemplatePageVo.class).contains(x.getProperty()))
                        .selectAs(DictionaryDetail::getName, FormTemplatePageVo::getCategoryName)
                        .leftJoin(DictionaryDetail.class, DictionaryDetail::getId, FormTemplate::getCategory)
                        .leftJoin(User.class, User::getId, FormTemplate::getCreateUserId));

        List<FormTemplatePageVo> records = page.getRecords();
        if (records.size() > 0){
            for (FormTemplatePageVo record : records) {
                if (record.getFormType() == YesOrNoEnum.NO.getCode()){//如果是系统表单的数据，需要返回给你类名等数据
                    //去menu表里面找道对应的功能名称和功能模块名称
                    Menu menu = menuService.getOne(Wrappers.<Menu>lambdaQuery().eq(Menu::getFormId, record.getId()));
                    if (menu != null) {
                        String[] split = menu.getComponent().split(StringPool.SLASH);
                        record.setFunctionalModule(split[1]);
                        record.setFunctionName(split[2]);
                    }
                }
            }
        }
        PageOutput<FormTemplatePageVo> pageOutput = ConventPage.getPageOutput(page);
        return R.ok(pageOutput);
    }

}

